#include "notifier.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QMenu>
#include <QDateTime>
#include <QSqlRecord>
#include <QAbstractTextDocumentLayout>
#include <QPainter>
#include <QMutexLocker>
#include "blogwizard.h"
//wpCommand::wpCommand(const QString& url, const QString& username, const QString& password, QObject* parent) : QObject(parent)
//{
//}
CommentsModel::CommentsModel( QObject * parent) : QAbstractListModel(parent)
{
}

CommentsModel::~CommentsModel()
{
	qDeleteAll(m_comments);
	m_comments.clear();
}

bool CommentsModel::removeRows(int row, int count, const QModelIndex & parent)
{
	if (count <= 0 || row < 0 || (row + count) > rowCount(parent))
        return false;
	beginRemoveRows(QModelIndex(), row, row + count - 1);

	for (int r = 0; r < count; ++r)
	{
		delete m_comments.takeAt(row);
	}

	endRemoveRows();
	return true;
}


QString CommentsModel::statusToString(Status status)
{
	QString s;
	switch (status)
	{
	case approve:
		s = "approve";
		break;
	case hold:
		s = "hold";
		break;
	case spam:
		s = "spam";
		break;
	}
	return s;
}


bool CommentsModel::getComments(const BlogSite& site, Status status, int offset, int number, int postid)
{
	if (!m_comments.isEmpty())
	{
		qDeleteAll(m_comments);
		m_comments.clear();
	}
	wpGetComments* cmd = new wpGetComments(site, this);
	cmd->execute(postid, statusToString(status), offset, number);
	connect(cmd, SIGNAL(success()), SLOT(getCommentsSuccess()));

	return true;
}

void CommentsModel::getCommentsSuccess()
{
	wpGetComments* cmd = static_cast<wpGetComments*>(sender());
	if (cmd)
	{
		foreach(Comment* c, cmd->m_comments)
		{
			CommentItem* item = new CommentItem();
			item->comment = c;
			item->doc.setUndoRedoEnabled(false);
			item->doc.setDocumentMargin( 0 );
			QTextOption textOption;
			//textOption.setWrapMode(wrapText ? QTextOption::WordWrap : QTextOption::ManualWrap);
			textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
			//textOption.setAlignment(QStyle::visualAlignment(option.direction, Qt::AlignLeft | Qt::AlignTop));
			item->doc.setDefaultTextOption(textOption);
			
			/*QString content = QString::fromUtf8(qPrintable(c->content));
			QString author = QString::fromUtf8(qPrintable(c->author));*/
			QString str = QString("<html><body><a href=\"http://www.deanlee.cn\">%1</a>%2<br /></body></html>").arg(c->author).arg(c->content);
			item->doc.setHtml(str);
			item->doc.adjustSize();
			m_comments << item;
		}
		//m_comments = cmd->m_comments;
		reset();
	}
}

QModelIndex CommentsModel::index ( int row, int column, const QModelIndex & parent) const 
{
	if (row < 0 || row >= m_comments.count() || column != 0)
		return QModelIndex();

	return createIndex(row, column, m_comments.value(row));
}

int CommentsModel::rowCount(const QModelIndex &parent) const
{
	return m_comments.count();
}

QVariant CommentsModel::data(const QModelIndex &index, int role) const
{
	return QVariant();
}


//int CommentItemDelegate::m_padding = 3;
#define COMMENT_PADDING 5
CommentItemDelegate::CommentItemDelegate(QObject* parent) : QStyledItemDelegate(parent),m_padding(COMMENT_PADDING)
{
}
CommentItemDelegate::~CommentItemDelegate()
{
}

void CommentItemDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
	if (index.column() != 0)
	{
		QStyledItemDelegate::paint(painter, option, index);
		return;
	}
	QStyleOptionViewItemV4 opt = option;
	initStyleOption(&opt, index);
	const QWidget *widget = opt.widget;
	QStyle *style = widget ? widget->style() : QApplication::style();
	style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, widget);

	CommentsModel* model = (CommentsModel*)index.model();
	//QSqlRecord r = model->record(index.row());
	CommentsModel::CommentItem* item = static_cast<CommentsModel::CommentItem*>(index.internalPointer());

	QTextDocument* doc = &item->doc;
	doc->setTextWidth(option.rect.width());
	QFontMetrics fm(doc->defaultFont());

	painter->save();
	QRect rcDraw = option.rect;
	rcDraw.adjust(m_padding, m_padding, -m_padding, -m_padding);
	/*rcDraw.adjust(style->pixelMetric(QStyle::PM_LayoutLeftMargin, &option), style->pixelMetric(QStyle::PM_LayoutTopMargin, &option),
		-style->pixelMetric(QStyle::PM_LayoutRightMargin, &option), -style->pixelMetric(QStyle::PM_LayoutBottomMargin, &option));*/
	QRect rcTop =rcDraw;
	rcTop.setBottom(rcTop.top() + fm.lineSpacing());
	QRect br;
	painter->drawText(rcTop, Qt::AlignRight | Qt::AlignVCenter | Qt::TextSingleLine, item->comment->dateDiff, &br);
	QFont f = option.font;
	f.setBold(true);
	painter->setFont(f);
	rcTop.setRight(br.left() - 3);
	painter->drawText(rcTop, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, 
		QFontMetrics(f).elidedText(item->comment->author, Qt::ElideRight, rcTop.width()), &br);
	item->rcAuthor = br;
	painter->setFont(option.font);
	QRect rcContent = rcDraw;
	rcContent.setTop(rcTop.bottom());
	rcContent.setBottom(rcContent.bottom() - 2 * fm.lineSpacing());
	painter->drawText(rcContent, Qt::AlignLeft | Qt::AlignTop | Qt::TextWrapAnywhere, item->comment->content, &br);
	// draw post title
	QRect rcPost = rcDraw;
	rcPost.setTop(rcContent.bottom());
	rcPost.setBottom(rcContent.bottom() + fm.lineSpacing());
	painter->drawText(rcPost, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
		fm.elidedText(item->comment->post_title, Qt::ElideRight, rcPost.width()), &br);
	item->rcPostTitle = br;
	//(option.rect.left(), rcTop.bottom(), option.rect.width(), option.rect.height() - 2 * fm.lineSpacing());
	if (option.state & QStyle::State_MouseOver)
	{
	/*	QRect rcCommand = rcDraw;
		rcCommand.setTop(rcContent.bottom());
		QTextDocument doc;
		doc.setHtml("<html><body><a href=\"dd\">afdsf</a> | <a href=\"cc\"> cccc</a> | </body></html>");
		doc.adjustSize();
		doc.setTextWidth(rcDraw.width());
		painter->translate(rcCommand.topLeft());
		doc.drawContents(painter, QRect(0, 0, rcCommand.width(), rcCommand.height()));*/
	}
	//painter->translate(labelRect.topLeft());// option.rect.topLeft() );
	//doc->drawContents(painter, labelRect);//, option.rect);
	//painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, r.value("author").toString());
	painter->restore();
	//   if( ( doc->idealWidth() + labelRect.height() ) <= labelRect.width() )
	//   {
	//     // The + rect.height() is to have a nicer effect when resizing the window :)
	//     doc->drawContents( painter, labelRect );
	//   }
	//   // ...otherwise (when the text goes over the available space) fade it away
	//   else
	//   {
	//     // Create a transparent image as big as the text label
	//     QImage image( labelRect.size(), QImage::Format_ARGB32 );
	//     image.fill( Qt::transparent );

	//     // create a linear gradient, white to transparent
	//     QLinearGradient gradient( QPoint( 0, 0 ), labelRect.bottomRight() );

	//     if( QApplication::isLeftToRight() )
	//     {
	//       gradient.setColorAt( 0.90, Qt::white       );
	//       gradient.setColorAt( 1.00, Qt::transparent );
	//     }
	//     else
	//     {
	//       gradient.setColorAt( 0.10, Qt::white       );
	//       gradient.setColorAt( 0.00, Qt::transparent );
	//     }

	//     // The painter will be used to blend the label with the gradient
	//     QPainter p( &image );
	//     p.translate( 0, 0 );
	//     //p.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing,
	//       //                true );

	//     // Paint the label over the image
	//     doc->drawContents( &p, labelRect );

	//     // Blend together the image and the gradient
	//     p.setCompositionMode( QPainter::CompositionMode_DestinationIn );
	//     p.fillRect( labelRect, QBrush( gradient ) );

	//     // Paint the resulting image over the widget
	//     painter->drawImage( labelRect, image );
	//   }
	
}

QSize CommentItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
	QSize size = QStyledItemDelegate::sizeHint(option, index);

	CommentsModel::CommentItem* item = static_cast<CommentsModel::CommentItem*>(index.internalPointer());
	QFontMetrics f(item->doc.defaultFont());
	size.setHeight(f.lineSpacing() * 6 + 2 * m_padding);
	//size.setHeight(80);
	return size;
}

//QTextDocument* CommentsModel::getDocument(const QModelIndex& index)
//{
//	QVariant data = QSqlTableModel::data(index, Qt::UserRole + 1);
//	QTextDocument* doc = NULL;
//	if (data.isNull())
//	{
//		doc = new QTextDocument(this);
//		doc->setUndoRedoEnabled(false);
//		doc->setDocumentMargin( 0 );
//
//		QSqlRecord r = record(index.row());
//		QString content = QString::fromUtf8(qPrintable(r.value("content").toString()));
//		QString author = QString::fromUtf8(qPrintable(r.value("author").toString()));
//		QString str = QString("<html><body><a href=\"http://www.deanlee.cn\">%1</a> %2<br /></body></html>").arg(author).arg(content);
//		doc->setHtml(str);
//		//doc->adjustSize();
//		QSqlTableModel::setData(index, qVariantFromValue((void*)doc), Qt::UserRole + 1);
//	}
//	else
//	{
//		void* pdoc = data.value<void*>();
//		doc = (QTextDocument*)pdoc;
//	}
//	return doc;
//}

NotifierWnd::NotifierWnd(QWidget* parent) : QWidget(parent)
{
	m_replyComment = NULL;
	createTray();
	m_refreshTimer = new QTimer(this);
	m_refreshTimer->setSingleShot(true);
	
	ui_.setupUi(this);
	ui_.lv_approved->setMouseTracking(true);
	m_model = new CommentsModel(this);
	m_delegate = new CommentItemDelegate(ui_.lv_approved);
	ui_.lv_approved->setModel(m_model);
	m_toolbar = new QLabel(ui_.lv_approved);
	m_toolbar->setContentsMargins(0, 0, 0, 0);
	m_toolbar->setTextFormat(Qt::RichText);
	m_toolbar->setOpenExternalLinks(false);
	m_toolbar->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
	m_toolbar->setText("<html><body><a href=\"unapprove\">Unapprove</a> | <a href=\"reply\">Reply</a> |"
		"<a href=\"edit\">Edit</a> | <a href=\"spam\">Spam</a> | <a href=\"delete\">Delete</a></body></html>");
	connect(m_toolbar, SIGNAL(linkActivated(const QString&)), SLOT(doCommand(const QString&)));
	m_toolbar->setVisible(false);
	ui_.lv_approved->setItemDelegate(m_delegate);
	connect(ui_.lv_approved, SIGNAL(entered(const QModelIndex&)), SLOT(itemEntered(const QModelIndex&)));


	// load sites
	QSqlQuery q;
	q.exec("select siteid, url, username, password, blog_name, blog_id, xmlrpc_url, is_admin from sites");
	while (q.next())
	{
		QSqlRecord r = q.record();
		BlogSite* site = new BlogSite();
		site->blog_id = r.value("blog_id").toInt();
		site->url = r.value("url").toString();
		site->username = r.value("username").toString();
		site->password = r.value("password").toString();
		site->blog_name = r.value("blog_name").toString();
		site->xmlrpc_url = r.value("xmlrpc_url").toString();
		site->blog_name = r.value("blog_name").toString();
		site->is_admin = r.value("is_admin").toBool();
		m_sites << site;
	}
	if (m_sites.count() == 0)
	{
		BlogWizard wizard(NULL);
		wizard.setModal(true);
		if (QDialog::Accepted == wizard.exec())
		{
			QSqlQuery qi;
			qi.prepare("insert into sites (url, username, password, blog_name, blog_id, xmlrpc_url, is_admin)"
					  "VALUES(?,?,?,?,?,?,?)");
			BlogSite* site = new BlogSite;
			*site = wizard.blogSite();
			qi.addBindValue(site->url);
			qi.addBindValue(site->username);
			qi.addBindValue(site->password);
			qi.addBindValue(site->blog_name);
			qi.addBindValue(site->blog_id);
			qi.addBindValue(site->xmlrpc_url);
			qi.addBindValue(site->is_admin);
			if (!qi.exec())
			{
				qDebug() << qi.lastError().text();
			}
			m_sites << site;
		}
	}
	if (m_sites.count() > 0)
	{
		setWindowTitle(m_sites.value(0)->blog_name);
	}

	connect(ui_.tb_approve, SIGNAL(toggled(bool)), SLOT(setChecked(bool)));
	connect(ui_.tb_hold, SIGNAL(toggled(bool)), SLOT(setChecked(bool)));
	connect(ui_.tb_spam, SIGNAL(toggled(bool)), SLOT(setChecked(bool)));
	connect(ui_.pb_send, SIGNAL(clicked()), SLOT(doNewComment()));
	connect(ui_.tb_refresh, SIGNAL(clicked()), SLOT(doRefresh()));
	connect(ui_.tb_config, SIGNAL(clicked()), SLOT(doConfig()));
	connect(m_model, SIGNAL(modelReset()), SLOT(modelReset()));
	connect(m_model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), SLOT(modelReset()));
	connect(ui_.lv_approved->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), SLOT(currentRowChanged(const QModelIndex &, const QModelIndex &)));

	ui_.tb_approve->click();
	QList<int> sizes;
	sizes << 500 << 0;
	ui_.splitter->setSizes(sizes);
	checkNewComments();
}

NotifierWnd::~NotifierWnd()
{
	delete m_tray;
	m_tray = NULL;
}
void NotifierWnd::modelReset()
{
	//if (!m_replyIndex.isValid())// || m_replyIndex.rowC)
	//{
	//	m_toolbar->setVisible(false);
	//}
}

void NotifierWnd::doRefresh()
{
}

void NotifierWnd::doConfig()
{

}

void NotifierWnd::setChecked(bool bChecked)
{
	static QToolButton* buttons[] = {ui_.tb_approve, ui_.tb_hold, ui_.tb_spam};
	//static QString iconName[] = {"eq/tab_contacts", "eq/tab_history", "eq/tab_chatroom"};
	QToolButton* btn = static_cast<QToolButton*>(sender());
	if (bChecked)
	{
		if (btn == ui_.tb_approve)
		{
			m_model->getComments(*m_sites.value(0), CommentsModel::approve, 0, 20);
		}
		else if (btn == ui_.tb_hold)
		{
			m_model->getComments(*m_sites.value(0), CommentsModel::hold, 0, 20);
		}
		else if (btn == ui_.tb_spam)
		{
			m_model->getComments(*m_sites.value(0), CommentsModel::spam, 0, 20);
		}
	}
	for (int i = 0; i < _countof(buttons); ++i)
	{
		if (btn == buttons[i] && bChecked)
		{
			//sw_contacts->setCurrentIndex(i);
			//btn->setChecked(true);
			//btn->setPsiIcon(IconsetFactory::iconPtr(iconName[i] + "_h"));
		}
		else
		{
			//buttons[i]->setPsiIcon(IconsetFactory::iconPtr(iconName[i]));
			//buttons[i]->setChecked(false);
		}
	}
}

void NotifierWnd::createTray()
{
	QAction* actExit = new QAction(tr("&Exit"), this);
	connect(actExit, SIGNAL(triggered(bool)), SLOT(closeProgram()));
	m_tray = new QSystemTrayIcon(this);
	m_tray->setIcon(QIcon(":/icons/comment.png"));
	m_trayMenu = new QMenu(this);
	m_trayMenu->addAction(actExit);
	m_tray->setContextMenu(m_trayMenu);
	//QMenu * msnMenu = new QMenu(this);
	m_tray->show();

	//m_trayMenu = new QMenu(this);
	connect(m_tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
}

void NotifierWnd::closeProgram()
{
	qApp->quit();
}

void NotifierWnd::closeEvent(QCloseEvent *e)
{
	hide();
	e->ignore();
	//if(d->tray) {
	//	trayHide();
	//	e->accept();
	//	return;
	//}

	//if(!askQuit()) {
	//	return;
	//}

	//closeProgram();

	//e->accept();
}


//void NotifierWnd::checkComments(BlogSite site)
//{
//	//wpGetComments
//}
void bringToFront(QWidget *widget)
{
	Q_ASSERT(widget);
	QWidget* w = widget->window();

#ifdef Q_WS_X11
	// If we're not on the current desktop, do the hide/show trick
	long dsk, curr_dsk;
	Window win = w->winId();
	if(desktopOfWindow(&win, &dsk) && currentDesktop(&curr_dsk)) {
		//qDebug() << "bringToFront current desktop=" << curr_dsk << " windowDesktop=" << dsk;
		if((dsk != curr_dsk) && (dsk != -1)) {  // second condition for sticky windows
			w->hide();
		}
	}

	// FIXME: multi-desktop hacks for Win and Mac required
#endif

	if(w->isMaximized())
		w->showMaximized();
	else
		w->showNormal();

	//if(grabFocus)
	//	w->setActiveWindow();
	w->raise();
	w->activateWindow();
}
void NotifierWnd::checkNewComments()
{
	//QtConcurrent::run(this, &NotifierWnd::checkComments, site)
	wpGetComments* cmd = new wpGetComments(*m_sites.value(0));
	// this will get comments status with 'approve' or 'hold'
	cmd->execute(0, "", 0, 20);

	// get spam
	wpGetComments* cmd2 = new wpGetComments(*m_sites.value(0));
	cmd2->execute(0, "spam", 0, 20);

}



void NotifierWnd::trayActivated(QSystemTrayIcon::ActivationReason reason)
{
	if (reason == QSystemTrayIcon::Trigger)
	{
		bringToFront(this);
	}
}
void NotifierWnd::doCommand(const QString& cmd)
{
	QModelIndex index = ui_.lv_approved->currentIndex();
	if (!index.isValid())
		return;
	CommentsModel::CommentItem* item = static_cast<CommentsModel::CommentItem*>(index.internalPointer());
	m_replyComment = item->comment;
	if (cmd == "unapprove")
	{
		wpEditComment* cmd = new wpEditComment(*m_sites.value(0));
		cmd->execute(m_replyComment->comment_id, "hold", QString());
		m_model->removeRow(index.row());
	}
	else if (cmd == "spam")
	{
		wpEditComment* cmd = new wpEditComment(*m_sites.value(0));
		cmd->execute(m_replyComment->comment_id, "spam", QString());
		// remove this item
		m_model->removeRow(index.row());
	}
	else if (cmd == "aprove")
	{
		wpEditComment* cmd = new wpEditComment(*m_sites.value(0));
		cmd->execute(m_replyComment->comment_id, "approve", QString());
		m_model->removeRow(index.row());
	}
	else if (cmd == "reply")
	{
	}
	else if (cmd == "delete")
	{
		wpDeleteComment* cmd = new wpDeleteComment(*m_sites.value(0));
		cmd->execute(m_replyComment->comment_id);
		m_model->removeRow(index.row());
	}
}

void NotifierWnd::doNewComment()
{
	if (m_replyComment)
	{
		wpNewComment* cmd = new wpNewComment(*m_sites.value(0));
		cmd->execute(m_replyComment->post_id, m_replyComment->comment_id, "testing client");
	}
}


void NotifierWnd::currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
	m_toolbar->setVisible(true);
	QRect rc = ui_.lv_approved->visualRect(current);
	QPoint pt = rc.bottomLeft();
	QRect rcBar = m_toolbar->rect();
	//pt.setX(pt.x() - rcBar.width());
	pt.setX(pt.x() + COMMENT_PADDING);
	pt.setY(pt.y() - rcBar.height() - COMMENT_PADDING);
	m_toolbar->move(pt);
}


void NotifierWnd::itemEntered(const QModelIndex& index)
{
	if (index.isValid())
	{
		
		ui_.lv_approved->setCurrentIndex(index);
		//m_replyIndex = index;
	}
	//int i = 0;
}


CheckCommentsThread::CheckCommentsThread(QObject* parent) : QThread(parent)
{
	m_bQuit = false;
}

CheckCommentsThread::~CheckCommentsThread()
{
	mutex.lock();
	m_bQuit = true;
	cond.wakeOne();
	mutex.unlock();
	wait();
}

void CheckCommentsThread::checkSite(const BlogSite& site)
{
	QMutexLocker locker(&mutex);
	/*this->hostName = hostName;
	this->port = port;*/
	if (!isRunning())
		start();
	else
		cond.wakeOne();
}


void CheckCommentsThread::run()
{
     while (!m_bQuit) {

        /* mutex.lock();
         QString fortune;
         in >> fortune;
         emit newFortune(fortune);

         cond.wait(&mutex);
         serverName = hostName;
         serverPort = port;
         mutex.unlock();*/
     }
}